
#include "clnt_connection.h"
#include "connect_mysql.h"


int readn(int fd, void *vptr, int n)
{
	int nleft;
	int nread;
	char *ptr;

	ptr =  (char*)vptr;
	nleft =  n;

	while(nleft > 0)
	{
		if((nread = read(fd, ptr, nleft)) < 0){

			if(errno == EINTR)
				nread = 0;

			else
				return(-1);
		}

		else if(nread == 0)	break;

		nleft -=  nread;
		ptr +=  nread;
	}

	return(n - nleft);
}


			


void* clnt_connection(void *arg)
{
	int clnt_sock = *((int *)arg);	// 파일 디스크립터
	short read_len = 0; 			
	short packet_len = 0;			// 패킷의 총 길이
	short protocol_type = 0;		// 프로토콜 타입
	
	char message[BUFSIZ];			// 패킷을 저장할 버퍼
	
	Coder coder;

	fprintf(stdout, "pthread_create()\n");

	while(1)
	{
		read_len = read(clnt_sock, message, HEADER_TOTAL_SIZE);
		if ( read_len == 0 )
		{
			// 서버와의 접속이 끊어지면 서버의 모든 애플리케이션을
			// 데이터베이스에서 모두 삭제한다.
//			AppServerStop(clnt_sock);
			fprintf(stdout, "접속이 종료 되었습니다\n");
			break;
		}


		packet_len  = *((short *)message);

		readn(clnt_sock, message + read_len, packet_len);   // 래퍼 함수

		coder.SetBuf(message);
		coder.GetHeader(&packet_len, &protocol_type);

		switch(protocol_type)
		{
			// 아이디를 체크
			case CLIENT_ID_CHECK :

				ClientIdCheck(clnt_sock, message);
				break;

			// 가입 승인
			case CLIENT_JOIN	 :

				ClientJoin(clnt_sock, message);
				break;
			
			// 로그인 승인
			case CLIENT_LOGIN	 :

				ClientLogin(clnt_sock, message);
				break;

			// 어플리케이션 서버 서비스 시작
			case AS_SERVICE_START:

				RequestProgramList(clnt_sock);
				break;

			// 어플리케이션 서버 프로그램 리스트 저장
			case AS_PROGRAM_LIST:

				AppProgramList(clnt_sock, message);
				break;


			// 아이콘 이미지 저장
			case AS_ICON_IMAGE:

				AppIconImage(clnt_sock, message);
				break;

			
		
		}
	}

}

void ClientIdCheck(int clnt_sock, char* message)
{
	Coder coder;
	USER user;
	char id_len = 0;
	char id_wns_msg[ID_ANSWER_SIZE];
	short id_wns_len = 0;

	coder.SetBuf(message);
	coder.GetChar(&id_len);
	coder.GetText(user.id, id_len);
	user.id[id_len] = '\0';


	//==========================
	// 데이터베이스와 연동하기
	//==========================

	mysql_idcheck(&user);	

	//==========================
	
	coder.SetBuf(id_wns_msg);
	coder.PutChar(user.result);
	id_wns_len = coder.SetHeader(ANSWER_ID_CHECK);

	write(clnt_sock, id_wns_msg, id_wns_len);

}

void ClientJoin(int clnt_sock, char* message)
{
	Coder coder;
	char id_len = 0;
	char pw_len = 0;
	char id_buf[USER_BUF_SIZE];
	char pw_buf[USER_BUF_SIZE];
	char join_wns_msg[ID_ANSWER_SIZE];
	short join_wns_len = 0;

	USER user;

	coder.SetBuf(message);
	coder.GetChar(&id_len);
	coder.GetText(user.id, id_len);
	coder.GetChar(&pw_len);
	coder.GetText(user.password, pw_len);
	user.id[id_len] = '\0';
	user.password[pw_len] = '\0';


	//==========================
	// 데이터베이스와 연동하기
	//==========================
	
	 mysql_joincheck(&user);

	//==========================
	
	coder.SetBuf(join_wns_msg);
	coder.PutChar(user.result);
	join_wns_len = coder.SetHeader(ANSWER_JOIN);
	
	write(clnt_sock, join_wns_msg, join_wns_len);

}


void ClientLogin(int clnt_sock, char* message)
{
	Coder coder;
	char id_len = 0;
	char pw_len = 0;
	char id_buf[USER_BUF_SIZE];
	char pw_buf[USER_BUF_SIZE];
	char login_wns_msg[ID_ANSWER_SIZE];
	short login_wns_len = 0;

	USER user;

	coder.SetBuf(message);
	coder.GetChar(&id_len);
	coder.GetText(user.id, id_len);
	coder.GetChar(&pw_len);
	coder.GetText(user.password, pw_len);

	user.id[id_len] = '\0';
	user.password[pw_len] = '\0';


	//==========================
	// 데이터베이스와 연동하기
	//==========================
	
	 mysql_logincheck(&user);

	//==========================
	
	coder.SetBuf(login_wns_msg);
	coder.PutChar(user.result);

	if(user.result == FAIL)
	{
		coder.PutChar(user.fail_reason);
	}

	login_wns_len = coder.SetHeader(ANSWER_LOGIN);

	write( clnt_sock, login_wns_msg, login_wns_len );

}



//====================================================================
// 어플리케이션 서버에게 프로그램 리스트를 받을 준비를 알리는 함수
//====================================================================
void RequestProgramList(int clnt_sock)
{
	printf("RequestProgramList()\n");
	char request_buf[5];
	Coder coder;
	short request_len;


	coder.SetBuf(request_buf);
	request_len = coder.SetHeader(REQUEST_PROGRAM_LIST);

	write(clnt_sock, request_buf, request_len);
	
}


//====================================================================
// 어플리케이션 서버에게 프로그램 리스트를 받는 함수
//====================================================================
void AppProgramList(int clnt_sock, char* message)
{
	printf("AppProgramList()\n");

	Coder coder;
	short name_len = 0;
	short path_len = 0;
	int clnt_addr_size;
	sockaddr_in clnt_addr;
	static char icon_path[ICON_PATH_SIZE];

	APP app;

	coder.SetBuf(message);
   coder.GetShort(&name_len);
   coder.GetText(app.name, name_len);

   coder.GetShort(&path_len);
	coder.GetText(app.apppath, path_len);


	// 어플리케이션의 이름과 절대경로를 저장한다.
	app.name[name_len] = '\0';
	app.apppath[path_len] = '\0';
   
   printf("app.name = %s\n", app.name);
   printf("app.apppath = %s\n", app.apppath);

	

	// 클라이언트의 IP를 알아낸다.
	clnt_addr_size = sizeof(clnt_addr);
	getpeername(clnt_sock, (struct sockaddr*)&clnt_addr, 
				(socklen_t*)&clnt_addr_size);
	printf("클라이언트의 IP를 얻어내었다..\n");			


	printf("데이터베이스 연동 전");
	//====================================================
	// 데이터베이스와 연동하기 (이름, 절대 경로, IP)
	//====================================================
	
	 mysql_app_list(&app, inet_ntoa(clnt_addr.sin_addr));

	//====================================================
	printf("데이터베이스 연동 후 \n");
	


	
	// 데이터베이스에 이름, 절대 경로, IP를 저장한 후에
	// 아이콘 이미지에 대해서 조사후에 처리하는 부분
	// 현재 위치에 아이콘 이미지가 존재하는지를 조사한다.
	printf("아이콘 파일이 있는지를 검사한다...\n");
   sprintf( icon_path, "/icons/%s.bmp", app.name );
	if( !access( icon_path, R_OK ) )
	{

		printf("%s가 존재 한다.\n", icon_path);

		// 이미지가 이미 존재하면 디비에 등록

		mysql_icon_load(app.name);

	}
	

	// 이미지가 존재하지 않으면 이미지를 서버에게 이미지를 요청한다.
	else
	{
      printf("아이콘 파일이 존재하지 않을시 리퀘스트를 요청한다...\n");
		char request_buf[5];
		Coder coder;
		short request_len;

		coder.SetBuf(request_buf);
		coder.PutShort(name_len);
		coder.PutText(app.name, name_len);


		request_len = coder.SetHeader(REQUEST_PROGRAM_ICON);

		write(clnt_sock, request_buf, request_len);
	}
	
	
}



//====================================================================
// 어플리케이션 서버에게 아이콘 이미지를 받는 함수
//====================================================================
void AppIconImage(int clnt_sock, char* message)
{
	Coder coder;
	short filename_len = 0;
	char fileis_end = 0;
	short filedata_len = 0;
	char filenamebuf[FILE_NAME_SIZE];
	char filename[FILE_NAME_SIZE];
	static int fd = -1;

	char appname[FILE_NAME_SIZE];

	coder.SetBuf(message);
	coder.GetShort(&filename_len);
	coder.GetText(filenamebuf, filename_len);
	coder.GetChar(&fileis_end);
	coder.GetShort(&filedata_len);

	filenamebuf[filename_len] = '\0';

	strcpy( appname, filenamebuf);

	
	// 리눅스 서버의 아이콘 디렉토리에 파일로 저장한다.
	strcpy(filenamebuf + filename_len, ".bmp");
	sprintf(filename, "/icons/%s", filenamebuf);


	if( fd == -1)
	{
		printf("filename : %s\n", filename );
		if((fd = open( filename, O_WRONLY | O_CREAT)) < 0)
		{
			perror("error");
			fprintf(stderr, "fileopen error\n");
			return;
		}
	}

	// 데이터를 받는 중에 들어왔을때 처리	
	write( fd, coder.Current(), filedata_len ); 


	if (fileis_end )
	{
		close(fd);
		fd = -1;

		// 아이콘 파일을 저장한후에 디비에 등록

		mysql_icon_load(appname);
	}
}

void AppServerStop(int clnt_sock)
{
	fprintf(stdout, "AppServerStop\n");
	int clnt_addr_size;
	sockaddr_in clnt_addr;


	// 클라이언트의 IP를 알아낸다.
	clnt_addr_size = sizeof(clnt_addr);
	getpeername(clnt_sock, (struct sockaddr*)&clnt_addr, 
				(socklen_t*)&clnt_addr_size);

	
	// 데이터베이스와 연동하여 얻오온 IP를 검색하여
	// 프로그램 리스트를 모두 삭제한다.
	mysql_server_stop(inet_ntoa(clnt_addr.sin_addr));
}
